#pragma once
#include "Dispatcher.hpp"
#include "SelectDispatcher.hpp"
#include "EpollDispatcher.hpp"
#include "PollDispatcher.hpp"
#include "Channel.hpp"
#include "EventLoop.hpp"
#include <thread>
#include <queue>
#include <map>
#include <mutex>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

using namespace std;
enum class ElemType : char
{
  ADD,
  DELETE,
  MODIFY
}; // 枚举后面＋：指定类型存储
// 定义任务节点
typedef struct ChannelElement
{
  ElemType type; // 处理节点方式
  Channel *channel;

} ChannelElement;
class Dispatcher;

class EventLoop
{
public:
  EventLoop()
      : EventLoop(string())
  {
  }
  EventLoop(const string threadName)
  {
    m_isQuit = false;
    m_threadID = this_thread::get_id();
    m_threadName == string() ? "mainthread" : threadName;
    m_dispatcher = new EpollDispatcher(this);
    // map
    m_channelMap.clear();
    int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, m_socketPair);
    if (ret == -1)
    {
      perror("socketpair");
      exit(0);
    }
#if 0
    //socketPair[0]:发送数据，socketPair[1]:接收数据
    class Channel* channel =new Channel(m_socketPair[1],FDEvent::ReadEvent,readLocalMessage,nullptr,nullptr,this);
    //channel添加到任务队列
#else
    auto obj = bind(&EventLoop::readMessage, this);
    // 对readMessage进行Bind操作是因为使用可调用对象包装器不能直接对类的非静态成员函数进行打包，需要通过绑定器进行绑定
    class Channel *channel = new Channel(m_socketPair[1], FDEvent::ReadEvent, obj, nullptr, nullptr, this);

#endif
    addTask(channel, ElemType::ADD);
  }
  ~EventLoop() {}
  // 启动模型
  int run()
  {
    m_isQuit = false;
    // 比较线程ID是否正常
    if (m_threadID != this_thread::get_id())
    {
      return -1;
    }
    // 循环进行事件处理
    while (!m_isQuit)
    {
      m_dispatcher->dispatch(); // 子线程解除阻塞后，通过任务处理函数来处理任务，两条路径：1.子线程解除阻塞并处理 2....
      processTaskQ();
    }
    return 0;
  }

  // 处理激活的文件描述符
  int eventActivate(int fd, int event) // 第二个参数：激活的文件描述符，第三个参数：激活的事件
  {
    if(fd<0) return -1;
    //
    Channel *channel = m_channelMap[fd];
    assert(channel->getSocket() == fd); 
    if (event & (int)FDEvent::ReadEvent && channel->readCallback)
    {
      channel->readCallback(const_cast<void *>(channel->getArg()));
    }
    if (event & (int)FDEvent::WriteEvent && channel->writeCallback)
    {
      channel->writeCallback(const_cast<void *>(channel->getArg()));
    }
    return 0;
  }
  // 添加任务到任务队列
  int addTask(Channel *channel, ElemType type)
  {
    // 加锁,保护共享资源
    m_mutex.lock();
    struct ChannelElement *node = new ChannelElement;
    node->channel = channel;
    node->type = type;
    m_taskQ.push(node); // 添加节点
    m_mutex.unlock();
    // 处理节点
    /*
    细节：1.链表节点的添加：可以是当前线程，也可以是其他线程（主线程）
            a.修改fd，当前线程发起，当前线程处理
            b.添加新的问价描述符，代表有新的客户端进行连接，主线程负责
        2.主线程不会处理任务队列，只负责与客户端进行新连接，子线程处理任务队列
    */
    if (m_threadID == this_thread::get_id())
    {
        // 当前子线程
        processTaskQ();
    }
    else
    {
        // 主线程通知子线程处理队列任务：1.子线程正在工作 2.子线程堵塞（dispatcher：epoll,poll,select）
        taskWakeup();
    }
    return 0;
}

  // 处理任务队列的任务
  int processTaskQ()
  {
    // 取出头节点
    while (!m_taskQ.empty())
    {
        m_mutex.lock();
        struct ChannelElement *node = m_taskQ.front();
        m_taskQ.pop();
        m_mutex.unlock();
        class Channel *channel = node->channel;
        if (node->type == ElemType::ADD)
        {
            // 添加
            add(channel);
        }
        else if (node->type == ElemType::DELETE)
        {
            // 删除
            remove(channel);
        }
        else if (node->type == ElemType::MODIFY)
        {
            // 修改
            modify(channel);
        }
        delete node;
    }

    return 0;
}


  // 处理dispatcher中的节点
  int add(Channel *channel)
  {
    int fd = channel->getSocket();
    // 找到fd对应的数组元素位置，并存储
    if (m_channelMap.find(fd) == m_channelMap.end())
    {
        m_channelMap.insert(make_pair(fd, channel));
        m_dispatcher->setChannel(channel);
        int ret = m_dispatcher->add();
        return ret;
    }
    return -1;
}
  int remove(Channel *channel)
  {
    int fd = channel->getSocket();
    if (m_channelMap.find(fd) == m_channelMap.end())
    {
        return -1;
    }
    m_dispatcher->setChannel(channel);
    int ret = m_dispatcher->remove();
    return ret;
  }
  int modify(Channel *channel)
  {
    int fd = channel->getSocket();
    if (m_channelMap.find(fd) == m_channelMap.end())
    {
        return -1;
    }
    m_dispatcher->setChannel(channel);
    int ret = m_dispatcher->modify();
    return ret;
}

  // 释放channel
  int freeChannel(Channel *channel)
  {
    // 删除channel和fd的对应关系
    auto it = m_channelMap.find(channel->getSocket());
    if(it !=m_channelMap.end())
    {
        m_channelMap.erase(it);
        close(channel->getSocket());
        delete channel;
    }
    return 0;
}
  static int readLocalMessage(void *arg)
  {
    class EventLoop *evLoop = static_cast<EventLoop *>(arg);
    char buf[256];
    read(evLoop->m_socketPair[1], buf, sizeof(buf));
    return 0;
  }
  int readMessage()
  {
    char buf[256];
    read(m_socketPair[1], buf, sizeof(buf));
    return 0;
  }
  // 返回线程id
  inline thread::id getThreadID()
  {
    return m_threadID;
  }

private:
  void taskWakeup()
  {
    const char *msg = "这是一个取消阻塞的函数";
    write(m_socketPair[0], msg, strlen(msg));
}

private:
  bool m_isQuit;
  // 该指针指向子类的实例对象：epoll ,poll,select
  Dispatcher *m_dispatcher;
  // 任务队列
  queue<ChannelElement *> m_taskQ;

  // map
  map<int, Channel *> m_channelMap;
  // 线程id,name,mutex
  thread::id m_threadID;
  string m_threadName;
  mutex m_mutex;
  int m_socketPair[2]; // 存储本地通信的fd通过socketpair初始化
};
